<template>
	<div
		:class="
			b({
				active: (state.active || state.overActive) && !props.readonly,
				move: state.moveActive,
				click: props.disabled
			})
		"
		@mousedown.stop="handleMove"
		@mouseover.stop="handleOver"
		@mouseout.stop="handleOut"
		:style="styleName">
		<el-input ref="input" class="drag_input" :class="b('focus')" v-model="state.value"></el-input>
		<div :class="b('wrapper')" ref="wrapper">
			<template v-if="(state.active || state.overActive || state.moveActive) && !props.readonly">
				<div :style="styleLineName" :class="b('line', ['left'])"></div>
				<div :style="styleLineName" :class="b('line', ['top'])"></div>
				<div :class="b('line', ['label'])" :style="styleLabelName">
					{{ state.baseLeft }},{{ state.baseTop }}
				</div>
			</template>
			<template v-if="!props.readonly">
				<template v-for="(item, index) in state.rangeList">
					<div
						:class="b('range', [item.classname])"
						:key="index"
						v-if="state.active"
						:style="[styleRangeName, getRangeStyle(item.classname)]"
						@mousedown.stop="rangeMove($event, item.classname)"></div>
				</template>
			</template>
			<div :class="b('menu')" :style="styleMenuName" v-show="state.active || state.overActive">
				<slot name="menu" :zIndex="props.zIndex" :index="props.index"></slot>
			</div>
			<div :class="b('item')" ref="item">
				<slot></slot>
			</div>
			<div :class="b('mask')" v-if="!props.disabled && props.mask"></div>
		</div>
	</div>
</template>

<script lang="ts" setup>
import { onMounted, reactive, toRefs, ref, computed, watch } from 'vue';
import b from '@CIF/Utils/bem.js';
import { getFixed, validatenull } from '@CIF/Utils/util';

const props = defineProps({
	index: {
		type: [String, Number],
		default() {
			return '';
		}
	},
	mask: {
		type: Boolean,
		default() {
			return true;
		}
	},
	scale: {
		type: Number,
		default() {
			return 1;
		}
	},
	readonly: {
		type: Boolean,
		default() {
			return false;
		}
	},
	resize: {
		type: Boolean,
		default() {
			return true;
		}
	},
	disabled: {
		type: Boolean,
		default() {
			return false;
		}
	},
	step: {
		type: Number,
		default() {
			return 1;
		}
	},
	zIndex: {
		type: [String, Number],
		default() {
			return 1;
		}
	},
	left: {
		type: Number,
		default() {
			return 0;
		}
	},
	top: {
		type: Number,
		default() {
			return 0;
		}
	},
	width: {
		type: Number,
		default() {
			return 0;
		}
	},
	height: {
		type: Number,
		default() {
			return 0;
		}
	}
});
const state: any = reactive({
	value: '',
	baseWidth: 0,
	baseHeight: 0,
	baseLeft: 0,
	baseTop: 0,
	children: {},
	moveActive: false,
	overActive: false,
	rangeActive: false,
	active: false,
	keyDown: null,
	rangeList: [
		{
			classname: 'left'
		},
		{
			classname: 'right'
		},
		{
			classname: 'top'
		},
		{
			classname: 'bottom'
		},
		{
			classname: 'top-left'
		},
		{
			classname: 'top-right'
		},
		{
			classname: 'bottom-left'
		},
		{
			classname: 'bottom-right'
		}
	]
});

const emit = defineEmits(['out', 'range', 'over', 'move', 'blur', 'focus']);

const scaleVal = computed(() => {
	return props.scale;
});
const styleMenuName = computed(() => {
	return {
		transformOrigin: '0 0',
		transform: `scale(${scaleVal.value})`
	};
});
const styleRangeName = computed(() => {
	const calc = 10 * scaleVal.value;
	return {
		width: setPx(calc),
		height: setPx(calc)
	};
});
const styleLabelName = computed(() => {
	return {
		fontSize: setPx(18 * scaleVal.value)
	};
});
const styleLineName = computed(() => {
	return {
		borderWidth: setPx(scaleVal.value)
	};
});
const styleName = computed(() => {
	return Object.assign(
		(() => {
			if (state.active) {
				return Object.assign(
					{
						zIndex: 9999
					},
					styleLineName.value
				);
			}
			return { zIndex: props.zIndex };
		})(),
		{
			top: setPx(state.baseTop),
			left: setPx(state.baseLeft),
			width: setPx(state.baseWidth),
			height: setPx(state.baseHeight)
		}
	);
});

watch(
	() => state.active,
	(val) => {
		if (val) {
			handleKeydown();
		} else {
			document.onkeydown = state.keyDown;
		}
	}
);
watch(
	() => props.width,
	(val) => {
		state.baseWidth = getFixed(val) || state.children.offsetWidth;
	}
);
watch(
	() => props.height,
	(val) => {
		state.baseHeight = getFixed(val) || state.children.offsetHeight;
	}
);
watch(
	() => props.left,
	(val) => {
		state.baseLeft = getFixed(val);
	}
);
watch(
	() => props.top,
	(val) => {
		state.baseTop = getFixed(val);
	}
);
const wrapper = ref();
watch(
	() => state.baseWidth,
	(val) => {
		wrapper.value.style.width = setPx(val);
		if (state.resize && state.children.style) {
			// state.children.offsetWidth = val
			state.children.style.width = setPx(val);
		}
	}
);
watch(
	() => state.baseHeight,
	(val) => {
		wrapper.value.style.height = setPx(val);
		if (state.resize && state.children.style) {
			// state.children.offsetHeight = val
			state.children.style.height = setPx(val);
		}
	}
);

function getRangeStyle(postion: any) {
	const calc = (10 * scaleVal.value) / 2;
	let result: any = {};
	let list = postion.split('-');
	list.forEach((ele: any) => {
		result[ele] = setPx(-calc);
	});
	return result;
}

function setPx(val: any, defval: any = '') {
	if (validatenull(val)) val = defval;
	if (validatenull(val)) return '';
	val = val + '';
	if (val.indexOf('%') === -1) {
		val = val + 'px';
	}
	return val;
}

const item = ref();
function init() {
	state.children = item.value.firstChild;
	state.baseWidth = getFixed(props.width) || state.children.offsetWidth;
	state.baseHeight = getFixed(props.height) || state.children.offsetHeight;
	state.baseLeft = getFixed(props.left);
	state.baseTop = getFixed(props.top);
	state.keyDown = document.onkeydown;
}

function setOverActive(val: any) {
	state.overActive = val;
}
function setActive(val: any) {
	state.active = val;
}

function rangeMove(e: any, position: any) {
	if (props.disabled) return;
	//移动的方向
	let x: any, y: any;
	//移动的位置
	let xp: any, yp: any;
	//移动的正负
	let xc: any, yc: any;
	state.rangeActive = true;
	handleMouseDown();
	let disX = e.clientX;
	let disY = e.clientY;
	document.onmousemove = (e) => {
		state.moveActive = true;
		if (position === 'right') {
			x = true;
			y = false;
		} else if (position === 'left') {
			x = true;
			xp = true;
			xc = true;
			y = false;
		} else if (position === 'top') {
			x = false;
			y = true;
			yp = true;
			yc = true;
		} else if (position === 'bottom') {
			x = false;
			y = true;
		} else if (position === 'bottom-right') {
			x = true;
			y = true;
		} else if (position === 'bottom-left') {
			x = true;
			y = true;
			xp = true;
			xc = true;
		} else if (position === 'top-right') {
			x = true;
			y = true;
			yp = true;
			yc = true;
		} else if (position === 'top-left') {
			x = true;
			y = true;
			xp = true;
			xc = true;
			yp = true;
			yc = true;
		}
		let left = e.clientX - disX;
		let top = e.clientY - disY;
		disX = e.clientX;
		disY = e.clientY;
		if (x) {
			let calc = left * props.step;
			if (xc) calc = -calc;
			if (xp) state.baseLeft = getFixed(state.baseLeft - calc);
			state.baseWidth = getFixed(state.baseWidth + calc);
		}
		if (y) {
			let calc = top * props.step;
			if (yc) calc = -calc;
			if (yp) state.baseTop = getFixed(state.baseTop - calc);
			state.baseHeight = getFixed(state.baseHeight + calc);
		}
		emit('range', {
			index: props.index,
			width: state.baseWidth,
			height: state.baseHeight,
			left: state.baseLeft,
			top: state.baseTop
		});
	};
	handleClear();
}

function handleOut() {
	state.overActive = false;
	emit('out', {
		index: props.index,
		width: state.baseWidth,
		height: state.baseHeight,
		left: state.baseLeft,
		top: state.baseTop
	});
}

function handleOver() {
	if (props.disabled) return;
	state.overActive = true;
	emit('over', {
		index: props.index,
		width: state.baseWidth,
		height: state.baseHeight,
		left: state.baseLeft,
		top: state.baseTop
	});
}

const input = ref();
function handleMove(e: any) {
	// console.log('777777777777e', e);
	if (props.disabled) return;
	setTimeout(() => {
		input.value.focus();
	});
	state.active = true;
	handleMouseDown();
	let disX = e.clientX;
	let disY = e.clientY;
	document.onmousemove = (e1: any) => {
		// console.log('777777777777e1', e1);
		let left = e1.clientX - disX;
		let top = e1.clientY - disY;
		disX = e1.clientX;
		disY = e1.clientY;
		state.baseLeft = getFixed(state.baseLeft + left * props.step);
		state.baseTop = getFixed(state.baseTop + top * props.step);
		emit('move', {
			index: props.index,
			width: state.baseWidth,
			height: state.baseHeight,
			left: state.baseLeft,
			top: state.baseTop
		});
	};
	handleClear();
}
function handleClear() {
	document.onmouseup = () => {
		document.onmousemove = null;
		document.onmouseup = null;
		handleMouseUp();
	};
}
function handleKeydown() {
	document.onkeydown = (event) => {
		let e = event || window.event || arguments.callee.caller.arguments[0];
		let step = 1 * props.step;
		if (input.value.focused) {
			if (e && e.keyCode == 38) {
				//上
				state.baseTop = getFixed(state.baseTop - step);
			} else if (e && e.keyCode == 37) {
				//左
				state.baseLeft = getFixed(state.baseLeft - step);
			} else if (e && e.keyCode == 40) {
				//下
				state.baseTop = getFixed(state.baseTop + step);
			} else if (e && e.keyCode == 39) {
				//右
				state.baseLeft = getFixed(state.baseLeft + step);
			}
			event.stopPropagation();
			event.preventDefault();
			emit('blur', {
				index: props.index,
				width: state.baseWidth,
				height: state.baseHeight,
				left: state.baseLeft,
				top: state.baseTop
			});
			state.keyDown && state.keyDown(event);
		}
	};
}

function handleMouseDown() {
	state.moveActive = true;
	emit('focus', {
		index: props.index,
		width: state.baseWidth,
		height: state.baseHeight,
		left: state.baseLeft,
		top: state.baseTop
	});
}
function handleMouseUp() {
	state.moveActive = false;
	state.rangeActive = false;
	// state.active = false;
	emit('blur', {
		index: props.index,
		width: state.baseWidth,
		height: state.baseHeight,
		left: state.baseLeft,
		top: state.baseTop
	});
}

onMounted(() => {
	init();
});
defineExpose({ ...toRefs(state), setActive, setOverActive });
</script>

<style lang="scss" scoped>
.cif-draggable {
	/* padding: 10px; */
	position: absolute;
	/* cursor: move; */
	-webkit-tap-highlight-color: transparent;
	-webkit-user-select: none;
	-moz-user-select: none;
	-ms-user-select: none;
	user-select: none;
}
.cif-draggable--active {
	cursor: move;
	border: 1px dashed #09f;
	background-color: rgba(115, 170, 229, 0.5);

	.cif-draggable__item {
		pointer-events: none !important;
	}
}
:deep(.el-input .drag_input) {
	position: relative;
	font-size: 14px;
	display: inline-block;
	width: 100%;

	.el-input__inner {
		-webkit-appearance: none;
		background-color: #fff;
		background-image: none;
		border-radius: 4px;
		border: 1px solid #dcdfe6;
		-webkit-box-sizing: border-box;
		box-sizing: border-box;
		color: #606266;
		display: inline-block;
		font-size: inherit;
		height: 40px;
		line-height: 40px;
		outline: 0;
		padding: 0 15px;
		-webkit-transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
		transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
		width: 100%;
	}
}
.cif-draggable__focus {
	opacity: 0;
	position: absolute !important;
	top: 0;
	left: 0;
	z-index: -1024;
}
.cif-draggable__line--left {
	position: absolute;
	border-top: 1px dashed #09f;
	width: 10000px;
	height: 0;
	top: 0;
	-webkit-transform: translateX(-100%);
	transform: translateX(-100%);
}
.cif-draggable__line--top {
	position: absolute;
	border-left: 1px dashed #09f;
	width: 0;
	height: 10000px;
	left: 0;
	-webkit-transform: translateY(-100%);
	transform: translateY(-100%);
}
.cif-draggable__line--label {
	top: -5px;
	left: -8px;
	position: absolute;
	padding: 5px;
	-webkit-transform: translate(-100%, -100%);
	transform: translate(-100%, -100%);
	color: #09f;
	font-size: 18px;
	white-space: nowrap;
	cursor: move;
}
.cif-draggable__range--left {
	left: -6px;
}
.cif-draggable__range--right {
	right: -6px;
}
.cif-draggable__range--top {
	top: -6px;
}
.cif-draggable__range--bottom {
	bottom: -6px;
}
.cif-draggable__range--top-left {
	top: -6px;
	left: -6px;
}
.cif-draggable__range--top-right {
	top: -6px;
	right: -6px;
}
.cif-draggable__range--bottom-left {
	bottom: -6px;
	left: -6px;
}
.cif-draggable__range--bottom-right {
	bottom: -6px;
	right: -6px;
}
.cif-draggable__range--left,
.cif-draggable__range--right {
	top: 50%;
	-webkit-transform: translateY(-50%);
	transform: translateY(-50%);
}
.cif-draggable__range--bottom,
.cif-draggable__range--top {
	left: 50%;
	-webkit-transform: translateX(-50%);
	transform: translateX(-50%);
}
.cif-draggable__range {
	position: absolute;
	width: 10px;
	height: 10px;
	border-radius: 100%;
	z-index: 9999;
	background-color: #09f;
}
.cif-draggable__menu {
	position: absolute;
	top: 0;
	left: 0;
	background-color: #409eff;
	font-size: 25px;
	color: #fff;
	z-index: 9999;
	cursor: pointer;
}
.cif-draggable__mask {
	width: 100%;
	height: 100%;
	border: 0;
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	z-index: 1;
}
</style>
